﻿using System.Text;

namespace Beeflys.Generator
{
    sealed class ProtocolResAdapterGenerator : IGenerator
    {
        private const string A_MESSENGER_RES_ADAPTER = "Beeflys.AMessengerResAdapter";

        public string Name => throw new NotImplementedException();

        private StringBuilder sb = new StringBuilder();

        public Dictionary<string, string> resAdapterMap = new Dictionary<string, string>();

        public void Start(UTypeInfo typeInfo)
        {
            var methods = typeInfo.Methods;
            for (int i = 0; i < methods.Count; i++)
            {
                var method = methods[i];
                var protocolId = method.GetProtocolId();
                var resAdapter = $"_{protocolId}_RES_ADAPTER";
                this.resAdapterMap.Add(protocolId, resAdapter);

                this.BuildResAdapter(resAdapter, method, typeInfo.FullName);
            }
        }
        

        private void BuildResAdapter(string resAdapterName, UMethodInfo method, string interfaceName)
        {
            string packName;

            sb.AppendLine("[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]");
            sb.AppendLine($"sealed class {resAdapterName}:{A_MESSENGER_RES_ADAPTER}");
            sb.AppendLine("{");
            sb.AppendLine("public override void Unfound(IActorContext context)");
            sb.AppendLine("{");

            sb.AppendLine(MessengerPackageUtil.BuildPackage(method.GetProtocolId(), 2, "null", "2", out packName));
            sb.AppendLine($"context.Sponsor.Respond({packName}, ActorOpencode.SUCCEED);");
            sb.AppendLine("}");

            var asyncStr = method.ReturnVoid ? string.Empty : "async";

            sb.AppendLine($"public override {asyncStr} Task Import(IActorContext context, object messenger)");
            sb.AppendLine("{");
            
            sb.AppendLine($"var impl = ({interfaceName})messenger;");

            var args = method.GetArgsTypes();
            
            if (args.Count > 0)
            {
                sb.AppendLine("var pack = (MessengerPackage)context.Request;");
                sb.AppendLine($"var data = ({method.GetReqPackName()})pack.data;");
            }
            
            if (!method.ReturnVoid)
            {
                var returnArgs = method.GetReturnType().GetGenericArguments();
                if (returnArgs.Count == 1)
                {
                    sb.Append("var result = ");
                }

                sb.Append("await");
            }

            sb.Append($" impl.{method.Name}");
            sb.Append("(");

            for (int i = 0; i < args.Count; i++)
            {
                var arg = args[i];
                sb.Append($"data.item{i}");

                if (i != args.Count - 1)
                {
                    sb.Append(",");
                }
            }

            

            sb.Append(");");
            sb.AppendLine();

            if (method.ReturnVoid)
            {
                sb.AppendLine("return Task.CompletedTask;");
            }
            else
            {
                
                var returnArgs = method.GetReturnType().GetGenericArguments();
                if (returnArgs.Count > 0)
                {
                    sb.AppendLine(MessengerPackageUtil.BuildPackage(method.GetProtocolId(), 2, "result", "1", out packName));
                }
                else
                {
                    sb.AppendLine(MessengerPackageUtil.BuildPackage(method.GetProtocolId(), 2, "null", "1", out packName));
                }

                sb.AppendLine($"context.Sponsor.Respond({packName}, ActorOpencode.SUCCEED);");
            }

            sb.AppendLine("}");
            sb.AppendLine("}");
        }




        public string Build()
        {
            return sb.ToString();
        }
    }
}
